/**
 * URL representation class
 * 
 * @author  Mykhailo Stadnyk <mikhus@gmail.com>
 * @package Jsl
 * @version 1.0
 */
Jsl.Url = Jsl.extend( Object, {

	/**
	 * Class constructor
	 * 
	 * @param {String} url
	 */
	constructor : function( url, phpCompat) {
		var url = url || document.location.href,
			phpCompat = Jsl.isDefined( phpCompat) ? phpCompat : false
		;
		Jsl.apply( this, Jsl.Url.parse( url));
		this.query = Jsl.Url.parseQuery( this.search, phpCompat);
		Jsl.Url.$super.constructor.call( this);
	},

	/**
	 * String representation of Jsl.Url object
	 * 
	 * @return {String}
	 */
	toString : function() {
		return this.href;
	}
});

/**
 * Static methods and properties
 */
Jsl.apply( Jsl.Url, {

	/**
	 * URL validate regex pattern
	 * 
	 * @type {RegExp}
	 */
	pattern : /^(?:([a-z]+):(?:([a-z]*):)?\/\/)?(?:([^:@]*)(?::([^:@]*))?@)?((?:[a-z0-9_-]+\.)+[a-z]{2,}|localhost|(?:(?:[01]?\d\d?|2[0-4]\d|25[0-5])\.){3}(?:(?:[01]?\d\d?|2[0-4]\d|25[0-5])))?(?::(\d+))?(?:([^:\?\#]+))?(?:\?([^\#]+))?(?:\#([^\s]+))?$/i,

	/**
	 * Checks if given string is a valid URL
	 * 
	 * @param  {String} url
	 * @return {Boolean}
	 */
	isValid : function( url) {
		return this.pattern.test( url);
	},

	/**
	 * Parses a url and returns it as parts representation
	 * 
	 * @param  {String} url
	 * @return {Object}
	 */
	parse : function( url) {
		var a = Jsl( '<a>'),
			r = { // parse result object
				'href'     : '',
				'protocol' : '',
				'hostname' : '',
				'host'     : '',
				'port'     : '',
				'pathname' : '',
				'search'   : '',
				'hash'     : ''
			}
		;
		a.href = url;
		for (var i in r) {
			r[i] = a[i];
		}
		r.host = r.host.replace( /:\d+/, ''); // IE is adding port to the host - remove it
		a = null; delete a; // remove the helper dom element
		return r;
	},

	/**
	 * Parses a QUERY_STRING
	 * 
	 * @param  {String} qs         - a query string
	 * @param  {Boolean} phpCompat - [Optional] PHP urlencode compatibility mode
	 * 
	 * @return {Jsl.Hash}
	 */
	parseQuery : function( qs, phpCompat) {
		var params = new Jsl.Hash();

		params.toString = function() {
			var str = '', sep = '&';
			this.each( function( value, name) {
				if (value instanceof Jsl.Hash)
					str += (str ? sep : '') + value.toString()
				; else
					str += (str ? sep : '') +
						Jsl.urlEncode( String( name), this._phpCompat) +
						(value !== false ? ('=' + Jsl.urlEncode( String( value), this._phpCompat)) : '')
				;
			});
			return str;
		};

		if (!qs) return params;

		if (Jsl.isString( qs)) { // parse to object first
			var pairs = qs.split( '&'), keys = {}, _params = {};
			for (var i = 0, s = pairs.length; i < s; i++) {
				var param = pairs[i].split( '='),
					name  = Jsl.urlDecode( param[0], phpCompat),
					value = Jsl.isDefined( param[1]) ? Jsl.urlDecode( param[1], phpCompat) : false
				;
				if ((m = name.match( /(.*?)\[(.*?)\]/))) {
					var name = m[1], key = m[2];
					if (key == '') {
						!Jsl.isDefined( keys[name]) ? (keys[name] = 0) : (keys[name] += 1);
						key = keys[name];
					}
					!Jsl.isDefined( _params[name]) && (_params[name] = {});
					_params[name][key] = value;
				} else
					_params[name] = value
				;
			}
			qs = _params;
		}

		if (Jsl.isObject( qs)) { // makes query string hash from params object
			Jsl.each( qs, function( value, name) {
				if (Jsl.isObject( value) || Jsl.isArray( value)) {
					value = new Jsl.Hash( value);
					value.toString = function() {
						var str = '', sep = '&';
						this.each( function( v, k) {
							str += (str ? sep : '') +
								Jsl.urlEncode( String( name), phpCompat) + '[' +
								Jsl.urlEncode( String( k), phpCompat) + ']' +
								(value !== false ? ('=' + Jsl.urlEncode( String( v), phpCompat)) : '')
							;
						});
						return str;
					};
				}
				params.set( name, value);
			});
		}

		return params;
	}
});
